﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ManagementConsole;
using SharpShare.Activation;
using System.ComponentModel;

namespace SharpShare.Management.Mmc.Nodes {
    public class ExtensionNode<TExtension> : ScopeNode where TExtension : IExtension {
        public ExtensionNode(IExtensionFactory<TExtension> factory, ExtensionDescriptor<TExtension> descriptor) {
            this.Factory = factory;
            this.Descriptor = descriptor;

            this.DisplayName = this.Descriptor.Name;

            this.ViewDescriptions.Add(new MessageViewDescription(this.Descriptor.Name, this.Descriptor.Description, MessageViewIcon.Information) {
                DisplayName = "Extension Information"
            });

            this.ViewDescriptions.Add(
                new MmcListViewDescription(MmcListViewOptions.SingleSelect) {
                    DisplayName = "Extensions",
                    ViewType = typeof(ExtensionsListView)
                });

            this.ViewDescriptions.DefaultIndex = (this.ViewDescriptions.Count - 1);

            this.ActionsPaneItems.Add(
                new Microsoft.ManagementConsole.Action("Add...", "Add a new extension.", (int)Icon.Add, "Add"));
        }

        public event EventHandler Changed;

        public IExtensionFactory<TExtension> Factory { get; private set; }
        public ExtensionDescriptor<TExtension> Descriptor { get; private set; }
        public int? InstanceImageIndex { get; set; }
        public IExtensionInstanceSelector<TExtension> InstanceSelector { get; set; }
        private TExtension AddingExtension { get; set; }

        protected virtual ExtensionInstanceNode<TExtension> CreateInstanceNode(TExtension extension) {
            var node = new ExtensionInstanceNode<TExtension>(extension, this.Factory) {
                ImageIndex = (this.InstanceImageIndex ?? this.ImageIndex),
                SelectedImageIndex = (this.InstanceImageIndex ?? this.SelectedImageIndex),
                InstanceSelector = this.InstanceSelector,
                Tag = extension
            };

            return node;
        }

        protected override void OnAction(Microsoft.ManagementConsole.Action action, AsyncStatus status) {
            base.OnAction(action, status);

            switch ((string)action.Tag) {
                case "Add": {
                        TExtension newExtension = this.Descriptor.Create();
                        newExtension.Name = "(untitled)";

                        ExtensionInstanceNode<TExtension> newExtensionNode = this.CreateInstanceNode(newExtension);
                        this.Children.Add(newExtensionNode);

                        this.OnChanged(this);

                        newExtensionNode.ShowPropertySheet("Properties");

                        break;
                    }
            }
        }

        protected override void OnExpand(AsyncStatus status) {
            base.OnExpand(status);

            this.Refresh();
        }

        public void Refresh(TExtension obj) {
            OnChanged(obj);
        }
        public void Refresh() {
            this.Children.Clear();

            this.Children.AddRange(
                this.Factory.ListExtensions()
                    .Where(e => this.Descriptor.ExtensionType.IsAssignableFrom(e.GetType()))
                    .Select(e => CreateInstanceNode(e))
                    .ToArray()
            );

            OnChanged(this);
        }

        private void OnChanged(object sender) {
            if (Changed != null) {
                try {
                    Changed(sender, EventArgs.Empty);
                } catch { }
            }
        }
        private class ExtensionsListView : Views.TypeDescriptorReportListView<TExtension> {
            public new ExtensionNode<TExtension> ScopeNode {
                get {
                    return (ExtensionNode<TExtension>)((MmcListView)this).ScopeNode;
                }
            }

            protected override IEnumerable<TExtension> ListReportObjects() {
                return this.ScopeNode.Children.Cast<ScopeNode>().Select(n => (TExtension)n.Tag);
            }

            protected override object GetDescriptionObject() {
                Type testInstance = this.ScopeNode.Descriptor.ExtensionType;
                return new ConfigurationElementTypeDescriptor(TypeDescriptor.GetProvider(testInstance).GetTypeDescriptor(testInstance));
            }

            protected override void OnInitialize(AsyncStatus status) {
                this.ScopeNode.Changed += new EventHandler(ExtensionNodeChanged);
                base.OnInitialize(status);
            }

            protected override void OnShutdown(SyncStatus status) {
                base.OnShutdown(status);

                this.ScopeNode.Changed -= ExtensionNodeChanged;
            }

            private void ExtensionNodeChanged(object sender, EventArgs e) {
                if (sender == this.ScopeNode) {
                    this.Refresh();
                } else {
                    this.Refresh((TExtension)sender);
                }
            }
        }
    }
}
